home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TurboTCP 1.0.1 / TurboTCP.source / CTCPAsyncCall.cp < prev    next >
Text File  |  1993-12-10  |  9KB  |  343 lines

  1. /*
  2. ** CTCPAsyncCall.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP asynchronous call class
  6. **
  7. **    Copyright © 1993, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTCPAsyncCall.h"
  13.  
  14. #include "CTCPDriver.h"
  15. #include "CTCPStream.h"
  16.  
  17.  
  18. //    —— initiate TCP calls ——
  19.  
  20. /*______________________________________________________________________
  21. **
  22. ** ITCPAsyncCall
  23. **
  24. **    Create a new TCP asynchronous call object. This object scheme, albeit complex, allows
  25. **    calls to be truly asynchronous. Control is returned immediately to the caller, which goes
  26. **    about other business until completion has occurred.
  27. **
  28. **        theStream (CTCPStream *):    the stream which requested the call
  29. **
  30. */
  31.  
  32. void CTCPAsyncCall::ITCPAsyncCall (CTCPStream *theStream)
  33.  
  34. {
  35.     itsStream = theStream;
  36.     qEntry.qSelfLink = this;
  37.     bypassTarget = NULL;
  38.     bypassProc = NULL;
  39.     MoveHHi((Handle) this);                // since we pass a pointer to the call block,
  40.     this->Lock(TRUE);                    //    the object can’t move
  41. }
  42.  
  43.  
  44. /*______________________________________________________________________
  45. **
  46. ** DoAsyncCall
  47. **
  48. **    Fills in the standard parameters for a TCP Device Manager call and executes the call.
  49. **
  50. **        theCsCode (short):                TCP operation code
  51. **        theParamBlockPtr (TCPiopb *):        parameter block for TCP call
  52. **
  53. **        return (OSErr):                    result code
  54. **
  55. */
  56.  
  57. OSErr CTCPAsyncCall::DoAsyncCall (short theCsCode, TCPiopb *theParamBlockPtr)
  58.  
  59. {
  60.     BlockMove(theParamBlockPtr, &itsParamBlock, sizeof (TCPiopb));
  61.     itsParamBlock.ioCompletion = (TCPIOCompletionProc) &CompletionProc;
  62.     itsParamBlock.ioCRefNum = gTCPDriver->GetTCPRefNum();
  63.     itsParamBlock.csCode = theCsCode;
  64.     PBControlAsync((ParmBlkPtr) &itsParamBlock);
  65.     return (itsParamBlock.ioResult);
  66. }
  67.  
  68.  
  69. //    —— process TCP call completion ——
  70.  
  71. /*______________________________________________________________________
  72. **
  73. ** ProcessCompletion
  74. **
  75. **    Respond to completion of this TCP call and all calls following it in the completion loop.
  76. **    After running through this loop, disposes of the call object, UNLESS it was a successful
  77. **    auto-receive call.
  78. **
  79. */
  80.  
  81. void CTCPAsyncCall::ProcessCompletion (void)
  82.  
  83. {
  84.     Boolean    disposeWhenDone;
  85.  
  86.     
  87.     // dispatch to general completion routine or to optimized routine for no-copy-receive calls
  88.  
  89.     TRY {
  90.         if (itsParamBlock.csCode == TCPNoCopyRcv)
  91.             disposeWhenDone = DispatchNoCopyRcv();
  92.         else
  93.             disposeWhenDone = Dispatch();
  94.         if (disposeWhenDone) {
  95.             itsStream->ProcessAsyncCompletion(this);
  96.             Dispose();
  97.         }
  98.     } CATCH {
  99.         itsStream->ProcessAsyncCompletion(this);
  100.         Dispose();
  101.     } ENDTRY;
  102.  
  103. }
  104.  
  105.  
  106. /*______________________________________________________________________
  107. **
  108. ** Dispatch (protected method)
  109. **
  110. **    Called by ProcessCompletion to report back to the CTCPStream object. Does not dispose
  111. **    of object. Also, does not handle TCPNoCopyRcv commands (see DispatchNoCopyRcv
  112. **    method below).
  113. **
  114. **        return (Boolean):    TRUE to dispose of call object when done
  115. **
  116. */
  117.  
  118. Boolean CTCPAsyncCall::Dispatch (void)
  119.  
  120. {
  121.     rdsEntry    *RDSPtr;
  122.     wdsEntry    *WDSPtr;
  123.  
  124.     if (itsParamBlock.ioResult) {
  125.  
  126.         // command failed, what was it?
  127.  
  128.         switch (itsParamBlock.csCode) {
  129.  
  130.             case TCPPassiveOpen:
  131.             case TCPActiveOpen:
  132.                 itsStream->HandleOpenFailed(itsParamBlock.ioResult);
  133.                 break;
  134.                 
  135.             case TCPSend:
  136.                 itsStream->HandleSendFailed((wdsEntry *) itsParamBlock.csParam.send.wdsPtr,
  137.                                         itsParamBlock.ioResult);
  138.                 break;
  139.  
  140.             case TCPRcv:
  141.                 if (itsParamBlock.ioResult == connectionClosing)
  142.                     break;
  143.             
  144.             case TCPClose:
  145.                 if (itsParamBlock.ioResult == connectionDoesntExist)
  146.                     break;
  147.  
  148.             default:
  149.                 itsStream->HandleTCPError(itsParamBlock.ioResult, itsParamBlock.csCode);
  150.                 break;
  151.  
  152.         }
  153.     }
  154.     else {
  155.  
  156.         // no error, dispatch success — what type of call was this anyway?
  157.  
  158.         switch (itsParamBlock.csCode) {
  159.     
  160.             case TCPPassiveOpen:
  161.             case TCPActiveOpen:
  162.                 itsStream->HandleOpened();
  163.                 break;
  164.     
  165.             case TCPSend:
  166.                 WDSPtr = (wdsEntry *) itsParamBlock.csParam.send.wdsPtr;
  167.                 itsStream->HandleDataSent(WDSPtr);
  168.                 if (itsParamBlock.csParam.open.security) {
  169.                     while ((*WDSPtr).length) {
  170.                         ForgetPtr((*WDSPtr).ptr);
  171.                         WDSPtr++;
  172.                     }
  173.                 }
  174.                 ForgetPtr(itsParamBlock.csParam.send.wdsPtr);
  175.                 break;
  176.  
  177.             case TCPRcv:
  178.                 if (itsParamBlock.csParam.receive.urgentFlag)
  179.                     itsStream->RcvUrgentBegin();
  180.                 if (itsParamBlock.csParam.receive.markFlag)
  181.                     itsStream->RcvUrgentMark();
  182.                 itsStream->HandleDataArrived(itsParamBlock.csParam.receive.rcvBuff,
  183.                                          itsParamBlock.csParam.receive.rcvBuffLen,
  184.                                           itsStream->RcvUrgentStatus());
  185.                 break;
  186.  
  187.             case TCPClose:
  188.                 itsStream->HandleClosed();
  189.                 break;
  190.  
  191.             case TCPRcvBfrReturn:
  192.  
  193.                 // if auto-receiving, re-issue the TCPNoCopyRcv command with same paramters
  194.                 
  195.                 if ((itsParamBlock.csParam.open.options[36]) && (itsStream->hasSessionOpen)) {
  196.                     itsParamBlock.csParam.receive.rdsLength = itsParamBlock.csParam.open.options[36];
  197.                     itsParamBlock.ioCompletion = (TCPIOCompletionProc) &CompletionProc;
  198.                     itsParamBlock.csCode = TCPNoCopyRcv;
  199.                     PBControlAsync((ParmBlkPtr) &itsParamBlock);
  200.                     return (FALSE);            // make sure call object stays around
  201.                 }
  202.                 else
  203.                     ForgetPtr(itsParamBlock.csParam.receive.rdsPtr);
  204.                 break;
  205.             
  206.         }    // switch
  207.     }        // if…else
  208.     
  209.     return (TRUE);                                // always dispose of call object when done
  210.  
  211. }
  212.  
  213.  
  214. /*______________________________________________________________________
  215. **
  216. ** DispatchNoCopyRcv (protected method)
  217. **
  218. **    Optimized routine to handle completion of TCPNoCopyRcv calls.
  219. **
  220. **        return (Boolean):    TRUE to dispose of call object when done
  221. **
  222. */
  223.  
  224. Boolean CTCPAsyncCall::DispatchNoCopyRcv (void)
  225.  
  226. {
  227.     rdsEntry    *RDSPtr;
  228.  
  229.  
  230.     // respond to error condition
  231.  
  232.     if (itsParamBlock.ioResult) {
  233.         if ((itsParamBlock.ioResult != connectionClosing) && (itsParamBlock.ioResult != connectionDoesntExist))
  234.             itsStream->HandleTCPError(itsParamBlock.ioResult, itsParamBlock.csCode);
  235.         ForgetPtr(itsParamBlock.csParam.receive.rdsPtr);
  236.         return (TRUE);                            // always dispose when call fails
  237.     }
  238.  
  239.  
  240.     // update urgent flags
  241.  
  242.     if (itsParamBlock.csParam.receive.urgentFlag)
  243.         itsStream->RcvUrgentBegin();
  244.     if (itsParamBlock.csParam.receive.markFlag)
  245.         itsStream->RcvUrgentMark();
  246.  
  247.  
  248.     // run through RDS and process each block of data
  249.  
  250.     RDSPtr = (rdsEntry *) itsParamBlock.csParam.receive.rdsPtr;
  251.     
  252.     while ((*RDSPtr).length) {
  253.         if (bypassProc)
  254.             (bypassProc) (bypassTarget, (*RDSPtr).ptr, (*RDSPtr).length, itsStream->rcvUrgent);
  255.         else
  256.             itsStream->HandleDataArrived((*RDSPtr).ptr,
  257.                     (*RDSPtr).length, itsStream->rcvUrgent);
  258.         RDSPtr++;
  259.     }
  260.  
  261.  
  262.     // return the buffers to MacTCP
  263.     
  264.     itsParamBlock.csCode = TCPRcvBfrReturn;
  265.     PBControlAsync((ParmBlkPtr) &itsParamBlock);
  266.  
  267.  
  268.     // if auto-receiving, the call will be reissued when the BfrReturn call is completed
  269.     
  270.     return (FALSE);            // keep call object around
  271.  
  272. }
  273.  
  274.  
  275. //    —— bypass procedure linkage ——
  276.  
  277. /*______________________________________________________________________
  278. **
  279. ** SetRcvBypassProc
  280. **
  281. **    Install a receive bypass procedure.
  282. **
  283. **        aRcvBypassTarget (CObject *):    the object to pass to the bypass procedure
  284. **        aRcvBypassProc (RcvBypassProc):    the receive bypass procedure
  285. **
  286. */
  287.  
  288. void CTCPAsyncCall::SetRcvBypassProc (CObject *aRcvBypassTarget,
  289.                                 RcvBypassProc aRcvBypassProc)
  290.  
  291. {
  292.     bypassTarget = aRcvBypassTarget;
  293.     bypassProc = aRcvBypassProc;
  294. }
  295.  
  296.  
  297. /***********************************************************************
  298. ************************************************************************
  299. **
  300. **    INTERRUPT-LEVEL routine follows. This routine cannot make memory allocations, cannot make
  301. **    synchronous TCP calls, and cannot use the Think C profiler.
  302. **
  303. */
  304.  
  305. #pragma options(!force_frame, !profile)
  306.  
  307.  
  308. // inline assembly code used by CompletionProc
  309.  
  310. #pragma parameter __A0 GetTheCall ()
  311. CTCPAsyncCall *GetTheCall (void) = {0x5988, 0x2050};        // SUBQ.L #4,A0
  312.     //                                            // MOVE.L (A0),A0
  313.     // remember that theCall->qEntry.qSelfLink is immediately before itsParamBlock
  314.  
  315.  
  316. //    —— completion procedure ——
  317.  
  318. /*______________________________________________________________________
  319. **
  320. ** CompletionProc (private static method)
  321. **
  322. **    The asynchronous completion routine. Recieves notification that any asynchronous
  323. **    TCP I/O operation has been completed. This routine is used for all TCP calls placed by
  324. **    CTCPAsyncCall::DoAsyncCall.
  325. **
  326. **    Send notification to the TCP driver object that this call has been completed. The driver
  327. **    then queues the call for processing at the next event loop.
  328. **
  329. **        register A0 (struct TCPiobp *):    the TCP I/O parameter block
  330. **
  331. */
  332.  
  333. pascal void CTCPAsyncCall::CompletionProc (void)
  334.  
  335. {
  336.     register CTCPAsyncCall    *theCall = GetTheCall();
  337.  
  338.     theCall->qEntry.qType = asyncCall;
  339.     Enqueue((QElemPtr) &(theCall->qEntry), &(gTCPDriver->asyncQueue));
  340.             // CTCPDriver::ProcessNetEvents will pick this up later
  341.  
  342. }
  343.